package com.rfid.project.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;

import biz.util.*;

import com.rfid.project.model.*;
import com.rfid.project.util.NumberUtil;
import com.rfid.project.dao.*;
import com.rfid.project.exception.CannotDelException;
import com.rfid.project.exception.CannotUpdateException;
import com.mysema.query.BooleanBuilder;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
@Transactional
public class ProjectDeliveryService {

	@Autowired
	private ProjectDeliveryDao projectDeliveryDao;
	private QProjectDelivery $ = QProjectDelivery.projectDelivery;
	
	@Autowired
	private ProjectDeliveryDetailDao projectDeliveryDetailDao;
	
	private QProjectDeliveryDetail $_projectDeliveryDetail = QProjectDeliveryDetail.projectDeliveryDetail;

	@Autowired
	private ProjectProductDao projectProductDao;
	
	private QProjectProduct $_projectProduct = QProjectProduct.projectProduct;
	
	@Autowired
	public void setProjectProductDao(ProjectProductDao projectProductDao) {
		this.projectProductDao = projectProductDao;
	}
	@Autowired
	private ProjectStakeholderDao projectStakeholderDao;
	
	private QProjectStakeholder $_projectStakeholder = QProjectStakeholder.projectStakeholder;
	
	@Autowired
	public void setProjectStakeholderDao(ProjectStakeholderDao projectStakeholderDao) {
		this.projectStakeholderDao = projectStakeholderDao;
	}

	@Autowired
	public void setProjectDeliveryDao(ProjectDeliveryDao projectDeliveryDao) {
		this.projectDeliveryDao = projectDeliveryDao;
	}
	
	@Autowired
	public void setProjectDeliveryDetailDao(ProjectDeliveryDetailDao projectDeliveryDetailDao) {
		this.projectDeliveryDetailDao = projectDeliveryDetailDao;
	}

	public List<ProjectDelivery> findAll() {
		return ListUtil.toList(projectDeliveryDao.findAll());
	}
	
	public ProjectDelivery findOne(Long id) {
		return this.projectDeliveryDao.findOne(id);
	}

	public List<ProjectDelivery> findAll(Long projectId, Long productId,
			Long inputPersonId, Long checkPersonId, String producer,
			String projectCode, String name, String batchNo, String spec,
			String unit, Date deliveryDateBegin, Date deliveryDateEnd,
			String ourHandler, String customerHandler, String deliveryAddress,
			Long deliveryWayId, String voucherNo, String remark,
			Date inputTimeBegin, Date inputTimeEnd, Date checkTimeBegin,
			Date checkTimeEnd, String status, String warrantyDate,
			String orderByAttribute) {
		BooleanBuilder condition = new BooleanBuilder();

		if (IdUtil.isNotEmpty(projectId)) {
			condition.and($.project.id.eq(projectId));
		}

		if (IdUtil.isNotEmpty(productId)) {
			condition.and($.product.id.eq(productId));
		}

		if (IdUtil.isNotEmpty(inputPersonId)) {
			condition.and($.inputPerson.id.eq(inputPersonId));
		}

		if (IdUtil.isNotEmpty(checkPersonId)) {
			condition.and($.checkPerson.id.eq(checkPersonId));
		}

		if (StringUtil.isNotEmpty(producer)) {
			condition.and($.producer.contains(producer));
		}

		if (StringUtil.isNotEmpty(projectCode)) {
			condition.and($.projectCode.contains(projectCode));
		}

		if (StringUtil.isNotEmpty(name)) {
			condition.and($.name.contains(name));
		}

		if (StringUtil.isNotEmpty(batchNo)) {
			condition.and($.batchNo.contains(batchNo));
		}

		if (StringUtil.isNotEmpty(spec)) {
			condition.and($.spec.contains(spec));
		}

		if (StringUtil.isNotEmpty(unit)) {
			condition.and($.unit.contains(unit));
		}

		if (deliveryDateBegin != null) {
			condition.and($.deliveryDate.after(deliveryDateBegin));
		}

		if (deliveryDateEnd != null) {
			condition.and($.deliveryDate.before(deliveryDateEnd));
		}

		if (StringUtil.isNotEmpty(ourHandler)) {
			condition.and($.ourHandler.contains(ourHandler));
		}

		if (StringUtil.isNotEmpty(customerHandler)) {
			condition.and($.customerHandler.contains(customerHandler));
		}

		if (StringUtil.isNotEmpty(deliveryAddress)) {
			condition.and($.deliveryAddress.contains(deliveryAddress));
		}

		if (IdUtil.isNotEmpty(deliveryWayId)) {
			condition.and($.deliveryWay.id.eq(deliveryWayId));
		}

		if (StringUtil.isNotEmpty(voucherNo)) {
			condition.and($.voucherNo.contains(voucherNo));
		}

		if (StringUtil.isNotEmpty(remark)) {
			condition.and($.remark.contains(remark));
		}

		if (inputTimeBegin != null) {
			condition.and($.inputTime.after(inputTimeBegin));
		}

		if (inputTimeEnd != null) {
			condition.and($.inputTime.before(inputTimeEnd));
		}

		if (checkTimeBegin != null) {
			condition.and($.checkTime.after(checkTimeBegin));
		}

		if (checkTimeEnd != null) {
			condition.and($.checkTime.before(checkTimeEnd));
		}

		if (StringUtil.isNotEmpty(status)) {
			condition.and($.status.contains(status));
		}

		if (StringUtil.isNotEmpty(warrantyDate)) {
			condition.and($.warrantyDate.contains(warrantyDate));
		}

		return ListUtil.toList(projectDeliveryDao.findAll(condition));
	}

	public Page<ProjectDelivery> findAll(Long projectId, Long productId,
			Long inputPersonId, Long checkPersonId, String producer,
			String projectCode, String name, String batchNo, String spec,
			String unit, Date deliveryDateBegin, Date deliveryDateEnd,
			String ourHandler, String customerHandler, String deliveryAddress,
			Long deliveryWayId, String voucherNo, String remark,
			Date inputTimeBegin, Date inputTimeEnd, Date checkTimeBegin,
			Date checkTimeEnd, String status, String warrantyDate,
			int pageNumber, int pageSize, String sortAttribute,
			String orderDirection) {
		BooleanBuilder condition = new BooleanBuilder();

		if (IdUtil.isNotEmpty(projectId)) {
			condition.and($.project.id.eq(projectId));
		}
		if (IdUtil.isNotEmpty(productId)) {
			condition.and($.product.id.eq(productId));
		}
		if (IdUtil.isNotEmpty(inputPersonId)) {
			condition.and($.inputPerson.id.eq(inputPersonId));
		}
		if (IdUtil.isNotEmpty(checkPersonId)) {
			condition.and($.checkPerson.id.eq(checkPersonId));
		}
		if (StringUtil.isNotEmpty(producer)) {
			condition.and($.producer.contains(producer));
		}
		if (StringUtil.isNotEmpty(projectCode)) {
			condition.and($.projectCode.contains(projectCode));
		}
		if (StringUtil.isNotEmpty(name)) {
			condition.and($.name.contains(name));
		}
		if (StringUtil.isNotEmpty(batchNo)) {
			condition.and($.batchNo.contains(batchNo));
		}
		if (StringUtil.isNotEmpty(spec)) {
			condition.and($.spec.contains(spec));
		}
		if (StringUtil.isNotEmpty(unit)) {
			condition.and($.unit.contains(unit));
		}
		if (deliveryDateBegin != null) {
			condition.and($.deliveryDate.after(deliveryDateBegin));
		}

		if (deliveryDateEnd != null) {
			condition.and($.deliveryDate.before(deliveryDateEnd));
		}
		if (StringUtil.isNotEmpty(ourHandler)) {
			condition.and($.ourHandler.contains(ourHandler));
		}
		if (StringUtil.isNotEmpty(customerHandler)) {
			condition.and($.customerHandler.contains(customerHandler));
		}
		if (StringUtil.isNotEmpty(deliveryAddress)) {
			condition.and($.deliveryAddress.contains(deliveryAddress));
		}
		if (IdUtil.isNotEmpty(deliveryWayId)) {
			condition.and($.deliveryWay.id.eq(deliveryWayId));
		}
		if (StringUtil.isNotEmpty(voucherNo)) {
			condition.and($.voucherNo.contains(voucherNo));
		}
		if (StringUtil.isNotEmpty(remark)) {
			condition.and($.remark.contains(remark));
		}
		if (inputTimeBegin != null) {
			condition.and($.inputTime.after(inputTimeBegin));
		}

		if (inputTimeEnd != null) {
			condition.and($.inputTime.before(inputTimeEnd));
		}
		if (checkTimeBegin != null) {
			condition.and($.checkTime.after(checkTimeBegin));
		}

		if (checkTimeEnd != null) {
			condition.and($.checkTime.before(checkTimeEnd));
		}
		if (StringUtil.isNotEmpty(status)) {
			condition.and($.status.contains(status));
		}
		if (StringUtil.isNotEmpty(warrantyDate)) {
			condition.and($.warrantyDate.contains(warrantyDate));
		}

		Sort sortObject = null;
		if (StringUtil.isEmpty(sortAttribute)) {
			sortObject = new Sort(Direction.DESC, "id");
		} else {
			sortObject = new Sort(Direction.fromStringOrNull(orderDirection),
					sortAttribute);
		}

		PageRequest pageRequest = new PageRequest(pageNumber - 1, pageSize,
				sortObject);
		return projectDeliveryDao.findAll(condition, pageRequest);
	}
	
	public void deleteProjectDelivery(Long id) throws CannotDelException{
		if (this.findProjectDelivery(id)) {
			throw new CannotDelException("该类型已经被交付物详情引用，请先删除交付物详情或修改交付物详情的引用！");
		} else {
			this.projectDeliveryDao.delete(id);
		}
	}
	private boolean findProjectDelivery(Long projectDeliveryId){
		BooleanBuilder condition = new BooleanBuilder();
		condition.and($_projectDeliveryDetail.projectDelivery.id.eq(projectDeliveryId));
		return this.projectDeliveryDetailDao.count(condition) > 0;
	}

	public void saveProjectDelivery(ProjectDelivery projectDelivery) {
		if(null == projectDelivery.getInputTime()){
			projectDelivery.setInputTime(DateUtil.nowDate());
		}
		Product product = projectDelivery.getProduct();
		if(null == product || null == product.getId()){
			projectDelivery.setProduct(null);
		}
		projectDeliveryDao.save(projectDelivery);
	}

	public List<ProjectDelivery> findByStatus(People people, Long projectStakeholderType, String status) {
		BooleanBuilder condition = new BooleanBuilder();
		condition.and(this.$_projectStakeholder.personID.eq(people.getId()));
		condition.and(this.$_projectStakeholder.projectStakeholderType.id.eq(projectStakeholderType));
		List<ProjectStakeholder> projectStakeholders = ListUtil.toList(this.projectStakeholderDao.findAll(condition));
		Set<Long> projectIds = new HashSet<Long>();
		for (ProjectStakeholder projectStakeholder : projectStakeholders) {
			projectIds.add(projectStakeholder.getProject().getId());
		}
		if(!projectIds.isEmpty()){
			condition = new BooleanBuilder();
			condition.and(this.$.project.id.in(projectIds));
			if(StringUtil.isNotEmpty(status)){
				condition.and($.status.eq(status));
			}
			return ListUtil.toList(this.projectDeliveryDao.findAll(condition));
		}
		return null;
	}

	public void commitProjectDelivery(ProjectDelivery projectDelivery) {
		ProjectDelivery sourceProjectDelivery = this.projectDeliveryDao.findOne(projectDelivery.getId());
		sourceProjectDelivery.setStatus(projectDelivery.getStatus());
		
		this.projectDeliveryDao.save(sourceProjectDelivery);
	}

	public void revocationProjectDeliveryFinishApply(ProjectDelivery projectDelivery) throws CannotUpdateException {
		ProjectDelivery sourceProjectDelivery = this.projectDeliveryDao.findOne(projectDelivery.getId());
		if(!ProcessStatus.FINISH_APPLY.equals(sourceProjectDelivery.getStatus())){
			throw new CannotUpdateException("该项目交付物发生变化，请刷新后再操作！");
		}
		sourceProjectDelivery.setStatus(projectDelivery.getStatus());
		
		this.projectDeliveryDao.save(sourceProjectDelivery);
	}

	public void checkProjectDelivery(ProjectDelivery projectDelivery) throws CannotUpdateException {
		ProjectDelivery sourceProjectDelivery = this.projectDeliveryDao.findOne(projectDelivery.getId());
		if(!ProcessStatus.FINISH_APPLY.equals(sourceProjectDelivery.getStatus())){
			throw new CannotUpdateException("该项目交付物发生变化，请刷新后再操作！");
		}
		sourceProjectDelivery.setCheckPerson(projectDelivery.getCheckPerson());
		sourceProjectDelivery.setCheckTime(DateUtil.nowDate());
		sourceProjectDelivery.setStatus(projectDelivery.getStatus());
		
		if(ProcessStatus.EXAMINE_SUCCESS.equals(projectDelivery.getStatus())){
			//更新交付计划的执行数量
			List<ProjectProduct> projectProducts = findProjectProductByProject(sourceProjectDelivery.getProject());
			for(int i = 0, sum = projectProducts.size(); i < sum; i++){
				ProjectProduct projectProduct = projectProducts.get(i);
				long deliveryProductId = sourceProjectDelivery.getProduct()==null ? -1 : sourceProjectDelivery.getProduct().getId();
				long planProductId = projectProduct.getProduct()==null? -2 : projectProduct.getProduct().getId();
				if(deliveryProductId == planProductId){
					projectProduct.setActualDeliveryNumber(NumberUtil.transition(projectProduct.getActualDeliveryNumber()) + NumberUtil.transition(sourceProjectDelivery.getDeliveryNumber()));
					this.projectProductDao.save(projectProduct);
				}
			}
		}
		this.projectDeliveryDao.save(sourceProjectDelivery);
	}
	
	private List<ProjectProduct> findProjectProductByProject(Project project){
		BooleanBuilder condition = new BooleanBuilder();
		condition.and(this.$_projectProduct.project.id.eq(project.getId()));
		return ListUtil.toList(this.projectProductDao.findAll(condition));
	}

}
